#include "socket_client.h"

#ifdef windows_x86
#include <ws2tcpip.h>
#define MSG_DONTWAIT 0x0
#endif
#ifdef RTE_APP
#include "plc_rte.h"
#endif

#include"logger_rte.h"

#ifdef USE_LWIP

#include "lwip/tcpip.h"
#include "lwip/sockets.h"

#endif


#ifdef SYLIXOS

#include "lwip/tcpip.h"
#include "lwip/sockets.h"

#define closesocket close
#endif

#include <csignal>

#ifdef windows_x86
#include <ws2tcpip.h>
#define MSG_DONTWAIT 0x0
#endif

int socket_client::begin(const char *host, uint16_t port)
{
    IP_ADDR = host;
    PORT = port;
    rtos::create_thread_run("client", 512, PriorityNormal, (void *) &thd_loop, this);
}


size_t socket_client::write(uint8_t b)
{
    txbuf.push_back(b);
    return 1;
}

size_t socket_client::write(const uint8_t *buf, size_t size)
{
    for(int i=0; i<size; i++)
    {
        txbuf.push_back(buf[i]);
    }
    return size;
}

int socket_client::available()
{
    return rx_head != rx_tail;
}

int socket_client::read()
{
    if (rx_head != rx_tail)
    {
        u8 c = rxbuf[rx_head];
        rx_head++;
        rx_head %= rx_size;
//        printf(" 0x%x ",c);
        return c;
    }
    return -1;
}

int socket_client::read(uint8_t *buf, size_t size)
{
    for (int i = 0; i < size; i++)
    {
        int c = read();
        if (c != -1)
            buf[i] = c;
        else return i;
    }
    return size;
}

int socket_client::peek()
{
    uint8_t b;
    // Unlike recv, peek doesn't check to see if there's any data available, so we must
    if (!available())
        return -1;
//    b = pbuf_get_at(_tcp_client->data.p, 0);
    return b;
}

void socket_client::flush()
{
    if(txbuf.size()>0)
    {
        send(sock, (const char *)txbuf.data(), txbuf.size(), MSG_DONTWAIT);
        txbuf.clear();
    }
}

void socket_client::stop()
{
}

uint8_t socket_client::connected()
{
}


// the next function allows us to use the client returned by
// EthernetServer::available() as the condition in an if-statement.

socket_client::operator bool()
{
}

void socket_client::loop()
{
#ifdef windows_x86
    WSADATA wsaData;

    int iResult;

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0)
    {
        logger.error("WSAStartup failed: %d\n", iResult);
        return ;
    }
#endif
    rxbuf = (uint8_t *) malloc(rx_size);
    while (true)
    {
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0)
        {
            logger.error("Socket error\n");
            rtos::Delay(10);
            continue;
        }

        client_addr.sin_family = AF_INET;
        client_addr.sin_port = htons(PORT);
        client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);
        memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));

        if (connect(sock, (struct sockaddr *) &client_addr, sizeof(struct sockaddr)) == -1)
        {
            logger.error("Connect failed!\n");
            closesocket(sock);
            rtos::Delay(10);
            continue;
        }
        int flag = 1;
        int result =setsockopt(sock,                   IPPROTO_TCP,                      TCP_NODELAY,                    (const char *)&flag,                    sizeof(int));
        if(result<0)
        {
            logger.error("setsockopt error");
        }
//        fcntl(sock,F_SETFL,flags&~O_NUNBLOCK); //设置成阻塞模式；
        logger.info("Connect to server %s:%d successful!\n", IP_ADDR, PORT);
        u8 *buf = (u8 *) malloc(rx_size);
        while (true)
        {
            int len = recv(sock, (char *) buf, rx_size, MSG_DONTWAIT);
            if (len < 0)
            {
                logger.error("connect error.");
                break;
            }
            for (int i = 0; i < len; i++)
            {
                rxbuf[rx_tail] = buf[i];
                rx_tail++;
                rx_tail %= rx_size;
//                printf("%x ,",buf[i]);
            }
//            printf("\n");
        }
        free(buf);
        closesocket(sock);
    }
    free(rxbuf);
}

